#ifndef OPENGL_CHECKER_H
#define OPENGL_CHECKER_H

namespace OGLChecker
{
  inline int checkFBO(GLenum fbo)
  {
    GLenum status = glCheckFramebufferStatus(fbo);
    if(status != GL_FRAMEBUFFER_COMPLETE)
    {
      switch (status)
      {
        case GL_FRAMEBUFFER_UNDEFINED:
          std::cerr << "FBO error: No window exists." << std::endl;
          break;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
          std::cerr << "FBO error: Incomplete attachment." << std::endl;
          break;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
          std::cerr << "FBO error: No RBO attached." << std::endl;
          break;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
          std::cerr << "FBO error: Attempt to draw in abscent RBO." << std::endl;
          break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
          std::cerr << "FBO error: Attempt to read from abscent RBO." << std::endl;
          break;
        case GL_FRAMEBUFFER_UNSUPPORTED:
          std::cerr << "FBO error: Unsupported format for RBO." << std::endl;
          break;
        case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
          std::cerr << "FBO error: Different number of samples in one FBO." << std::endl;
          break;
        case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
          std::cerr << "FBO error: Different number of layers in one FBO." << std::endl;
          break;
      }
    }
    return status;
  }
  
  inline int checkShaderCompilation(GLuint shader, const char* name)
  {
    GLint test;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &test);
    if(test == GL_FALSE)
    {
      char infoLog[1024];
      glGetShaderInfoLog(shader, 1024, NULL, infoLog);
      std::cerr << "The shader \"" << name << "\""
                << "  failed to compile with the following error:" << std::endl
                << infoLog << std::endl;

      return 1;
    }
    return 0;
  }
  inline int checkProgramLinking(GLuint program, const char* name)
  {
    GLint test;
    glGetProgramiv(program, GL_LINK_STATUS, &test);
    if(test == GL_FALSE)
    {
      char infoLog[1024];
      glGetProgramInfoLog(program, 1024, NULL, infoLog);
      std::cerr << "The program \"" << name << "\""
                << "  failed to link with the following error:" << std::endl
                << infoLog << std::endl;

      return 1;
    }
    return 0;
  }
  inline int getGlError()
  {
    GLenum error = glGetError();
    switch (error)
    {
      #define ERROR_CASE(code, desc) case(code): std::cerr << "OpenGL Error : " << desc << std::endl; return code;
          case 0: return 0;
          ERROR_CASE(GL_INVALID_ENUM, "Invalid Enum");
          ERROR_CASE(GL_INVALID_VALUE, "Invalid Value");
          ERROR_CASE(GL_INVALID_OPERATION, "Invalid Operation");
          ERROR_CASE(GL_INVALID_FRAMEBUFFER_OPERATION, "Invalid Framebuffer Operation");
          ERROR_CASE(GL_OUT_OF_MEMORY, "Out Of Memory");
          ERROR_CASE(GL_STACK_UNDERFLOW, "Stack Underflow");
          ERROR_CASE(GL_STACK_OVERFLOW, "Stack Overflow");
    }
    return -1;
  }
};

#endif
